package com.boarsoft.config.bean;


import java.io.Serializable;
import java.util.*;

/**
 * 配置变量本地存储结构
 */
public class MultiVerVar<T> implements Serializable {
    private static final long serialVersionUID = 3750817644158653712L;
    /**
     * 变量名
     */
    private String code;

    /**
     * 用于存储配置变量的多个版本，最新的值总是放在最后
     */
    private LinkedList<ConfigVarValue<T>> values;

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public LinkedList<ConfigVarValue<T>> getValues() {
        return values;
    }

    public void setValues(LinkedList<ConfigVarValue<T>> values) {
        this.values = values;
    }

    /**
     * 将json解析为MultiVerVar实例，添加到MultiVerVar
     * 格式： [{"time": "2024-05-10 12:54:38.000000", "value": "value0"},
     *         {"time": "2024-05-13 12:54:38.000000","value": "value3"}]
     * 其中time为 java.util.Date类型
     */
    public static void set(MultiVerVar var, LinkedList<ConfigVarValue> linkedList) throws Exception {
        //系统当前时间
        Date currDate = new Date();
        if (linkedList == null) {
            return;
        }
        Collections.sort(linkedList, new Comparator<ConfigVarValue>() {
            @Override
            public int compare(ConfigVarValue v1, ConfigVarValue v2) {
                return v2.getTime().compareTo(v1.getTime());
            }
        });

        /**
         * 检查 linkedList 中是否包含有效数据（判断依据：必须有一条的生效时间小于当前时间）
         * 即：根据生效时间降序以后最后一个元素的时间必须小于当前时间
         */
        if(linkedList.get(linkedList.size() - 1).getTime().getTime() > currDate.getTime()){
            throw new Exception("必须有一条的生效时间小于当前时间");
        }

        /**
         * 删除过期元素，
         * 原则：列表中只保留一条小于当前时间的配置
         */
        linkedList = removeExpire(linkedList, currDate);

        var.setValues(linkedList);
    }

    /**
     * 删除过期配置（注： 默认values是根据时间由大到小排序的）
     * 原则：列表中只保留一条小于当前时间的配置
     * @return
     */
    private static LinkedList<ConfigVarValue> removeExpire(LinkedList<ConfigVarValue> values, Date sysTime) {
        LinkedList<ConfigVarValue> list = new LinkedList<ConfigVarValue>();
        for(int i = 0; i < values.size(); i++){
            if(values.get(i).getTime().getTime() >= sysTime.getTime()){
                list.add(values.get(i));
            } else {
                list.add(values.get(i));
                return list;
            }
        }
        return list;
    }

    /**
     * 从List的尾部查找，取出生效时间早于请求时间的第一个值
     */
    public static Object get(MultiVerVar var, Date requestTime) throws Exception {
        //获取各版本变量（默认按时间由大到小排序）
        LinkedList<ConfigVarValue> values = var.getValues();
        if (values == null) {
            throw new Exception("变量列表为空！");
        }
//        Collections.sort(values, new Comparator<ConfigVarValue>() {
//            @Override
//            public int compare(ConfigVarValue v1, ConfigVarValue v2) {
//                return v1.getEffectTime().compareTo(v2.getEffectTime());
//            }
//        });
        //请求时间大于列表最大值
        if (requestTime.getTime() >= (values.get(0).getTime()).getTime()) {
            return values.get(0).getValue();
        }
        //请求时间小于列表最小值
        if (requestTime.getTime() < ((values.get(values.size() - 1)).getTime().getTime())) {
            throw new Exception("请求时间小于列表中的最小时间！");
        }
        //其他（前提，默认数据是从大到小排序的）
        for (int i = 0; i < values.size(); i++) {
            if (values.get(i).getTime().getTime() <= requestTime.getTime()) {
                return values.get(i).getValue();
            }
        }
        return values.get(values.size() - 1).getValue();
    }

    public static void add(MultiVerVar var, ConfigVarValue configVarValue) throws Exception {
        //系统当前时间
        Date currDate = new Date();
        if(configVarValue != null && configVarValue.getTime().getTime() >= currDate.getTime()){
            LinkedList<ConfigVarValue> values = var.getValues();
            if (values == null) {
                values = new LinkedList<>();
            }
            values.add(configVarValue);
            values.stream().sorted((v1, v2) -> (v2.getTime().compareTo(v1.getTime())));
            values = removeExpire(values, currDate);
            var.setValues(values);
        }
    }

}
